#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <linux/mman.h>

#include <string.h>

#include "bmp.h"
typedef struct fb_info_t{
	int fb_length;
	int line_length;
	int width;
	int height;
	int bitsperpixel;
}fb_info,*p_fb_info;

int s_enable_snap = 0;//截图
char *s_snap_filename=NULL;

int s_enable_info = 0;//查看信息
char *s_fb_dev=NULL;

int snap_to_bmp(char *fb_dev,fb_info *p_info,char *snap_filename)
{
	int ret=0;
	int fp=0;
	fp=open(fb_dev,O_RDWR);
	if(fp <0){
		printf("framebuffer device[%s] open fail!\n",fb_dev);
		return 1;
	}
	
	ClImage image;
	memset(&image,0,sizeof(image));

	int len=p_info->fb_length;
	char *buffer=(char *)malloc(len);
	image.imageData = buffer;
	
	image.width=p_info->width;
	image.height=p_info->height;
	switch(p_info->bitsperpixel){
	case 8:
		image.channels=1;
		break;
	case 24:
		image.channels=3;
		break;
	default:
		printf("device[%s] is not supported!\n",fb_dev);
		close(fp);
		return 2;
	}
	memset(buffer,0,len);
	while(len>0){
		ret=read(fp,buffer,len);
		if(ret>0){
			len -=ret;
			buffer +=ret;
		}else {
			break;
		}
	}
	printf("read bytes[%d] len[%d]\n",(int)buffer - (int)image.imageData,len);
	close(fp);
	ret=clSaveImage(snap_filename,&image);
	if(ret!=0){
		printf("save file[%s] fail!\n",snap_filename);
		return 3;
	}
	return 0;
}

void dump_fb_info(char *fb_dev,fb_info *p_info)
{	
	printf("framebuffer device	:%s \n",fb_dev);
	printf("The mem is		:%d \n",p_info->fb_length);
	printf("The mem line length	:%d \n",p_info->line_length);
	printf("The xres is		:%d \n",p_info->width);
	printf("The yres is		:%d \n",p_info->height);
	printf("Bits per pixel is	:%d \n",p_info->bitsperpixel);
}

int get_fb_inof(char *fb_dev,fb_info *p_info)
{
	int ret=0;
	int fp=0;

	struct fb_var_screeninfo vinfo;
	struct fb_fix_screeninfo finfo;
	memset(&vinfo,0,sizeof(struct fb_var_screeninfo));
	memset(&finfo,0,sizeof(struct fb_fix_screeninfo));	

	fp=open(fb_dev,O_RDWR);
	if(fp <0){
		printf("framebuffer device[%s] open fail!\n",fb_dev);
		return 1;
	}

	if(ioctl(fp,FBIOGET_FSCREENINFO,&finfo) !=0){
		printf("error when reading framebuffer info\n");
		return 2;
	}
	
	if(ioctl(fp,FBIOGET_VSCREENINFO,&vinfo) !=0){
		printf("error when reading framebuffer info\n");
		return 3;
	}
	close(fp);
	
	p_info->fb_length = finfo.smem_len;
	p_info->line_length=finfo.line_length;
	p_info->width=vinfo.xres;
	p_info->height=vinfo.yres;
	p_info->bitsperpixel=vinfo.bits_per_pixel;
	return 0;
}

void usage(int argc,char *argv[])
{
	printf("command format:%s /dev/fb0 -i -o out.bmp\n",argv[0]);
	printf("	-i output framebuffer information\n");
	printf("	-o out.bmp output snap bmp file\n");
}

int optparse(int argc,char *argv[])
{
	int i=0;
	int ret=0;

	for(i=1;i<argc;i++){
		if(strcmp(argv[i],"-o") == 0){
			s_enable_snap = 1;
			if(argc > i +1){
				s_snap_filename=argv[i+1];
			}
			i++;
			continue;
		}
		if(strcmp(argv[i],"-i") == 0){
			s_enable_info = 1;
			continue;
		}
		if(strncmp(argv[i],"/dev/fb",7) == 0){
			if(s_fb_dev == NULL){
				s_fb_dev=argv[i];
			}
			continue;
		}
		printf("wrong paremeter:%s!\n",argv[i]);
		ret=1;
		break;		
	}
	return ret;
}

int main(int argc,char *argv[])
{
	int ret=0;
	 
	printf("%s %d argc:%d\n",__FUNCTION__,__LINE__,argc);
	if(argc>=2){
		ret=optparse(argc,argv);
	}else{
		s_fb_dev="/dev/fb0";
	}
	if(ret !=0){
		usage(argc,argv);
		return 1;
	}
	
	fb_info my_fb_info;
	memset(&my_fb_info,0,sizeof(fb_info));
	if(s_enable_info == 1 || s_fb_dev!=NULL){
		//输出framebuffer设备信息
		ret=get_fb_inof(s_fb_dev,&my_fb_info);
		if(ret!=0){
			printf("fail to get fb[%s] info!\n",s_fb_dev);
			return 2;
		}
		dump_fb_info(s_fb_dev,&my_fb_info);
	}
	
	if(s_enable_snap == 1){
		ret=snap_to_bmp(s_fb_dev,&my_fb_info,s_snap_filename);
		if(ret!=0){
			printf("fail to get snap from device[%s]!\n",s_fb_dev);
			return 3;
		}
	}
	
        return 0;
}

